﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace Framework.Core.Dependency.Domain
{
    [DataContract, KnownType(typeof(Module)), KnownType(typeof(Language)), KnownType(typeof(Project))]
    public class Solution : IEquatable<Solution>
    {
        private HashSet<Project> projects;
        private HashSet<string> versionControlPath;

        private Solution()
        {
            projects = new HashSet<Project>();
            VersionControlPath = new HashSet<string>();
            Projects = new List<Project>();
        }

        public Solution(string name, string extension, string path, Language language, string rootPath)
            : this()
        {
            Name = name;
            Extension = extension;
            Language = language;
            Path = path;

            if (!string.IsNullOrWhiteSpace(rootPath))
            {
                AddVersionControlPath(System.IO.Path.GetDirectoryName(path), rootPath);
            }
        }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public IEnumerable<string> VersionControlPath
        {
            get { return versionControlPath; }
            set { versionControlPath = new HashSet<string>(value); }
        }

        [DataMember]
        public string Path { get; set; }

        [DataMember]
        public string Extension { get; set; }

        [DataMember]
        public Language Language { get; set; }

        [DataMember]
        public IEnumerable<Project> Projects
        {
            get { return projects; }
            set { projects = new HashSet<Project>(value); }
        }

        public bool Equals(Solution other)
        {
            return string.Equals(Path, other.Path, StringComparison.InvariantCultureIgnoreCase);
        }

        public override string ToString()
        {
            return Name;
        }

        private void AddVersionControlPath(string vcp, string branch)
        {
            var candidate = vcp.Replace(branch, "$").Replace(@"\", "/");
            if (!versionControlPath.Any(candidate.StartsWith))
            {
                versionControlPath.Add(candidate);
            }
        }

        public void AddProject(Project project, string branch)
        {
            projects.Add(project);

            var directories = projects
                .SelectMany(x => x.Files)
                .Where(f => !f.EndsWith(@"GlobalAssemblyInfo.cs"))
                .Select(GetDirectory).Distinct().ToList();

            directories.ForEach(d => AddVersionControlPath(d, branch));
        }

        private string GetDirectory(string f)
        {
            var solutionFullPath = System.IO.Path.GetDirectoryName(Path);
            var filePath = System.IO.Path.Combine(solutionFullPath.SafeTrim(), f.SafeTrim());
            var cleanedFilePath = System.IO.Path.GetFullPath(filePath);
            return System.IO.Path.GetDirectoryName(cleanedFilePath);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != GetType())
            {
                return false;
            }
            return Equals((Solution)obj);
        }

        public override int GetHashCode()
        {
            return (Path != null ? Path.ToLower().GetHashCode() : 0);
        }
    }
}